home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / backup / dds2tar-.000 / dds2tar-2.4.12.tar / dds2tar-2.4.12 / dds_extract.c < prev    next >
C/C++ Source or Header  |  1996-03-29  |  11KB  |  489 lines

  1.  
  2. /*
  3.  * This file is part of dds2tar.
  4.  * Copyright by J"org Weule
  5.  */
  6.  
  7. #include <stdlib.h>
  8. #include <stdio.h>
  9. #include <sys/mtio.h>
  10. #include <string.h>
  11. #include <unistd.h>
  12. #include <fnmatch.h>
  13.  
  14. #include "dds2tar.h"
  15. #include "dds_tape.h"
  16.  
  17. /*
  18.  * To count the number of blocks written, we use the variable nblocks.
  19.  */
  20. static int nblocks = 0;
  21.  
  22. /*
  23.  * Fill the buffer 'cur_block' the block of the given number.
  24.  * first we check the block number of the copy that is hold inside the
  25.  * buffer cur_block.
  26.  */
  27. static int
  28. set_cur_block(int const sb)
  29. {
  30.     int     n;
  31.  
  32. #ifdef DDS_TRACE
  33.     fprintf(stderr,"%d\n",__LINE__);
  34.     fprintf(stderr, "set_cur_block(%d)\n", sb);
  35. #endif
  36.  
  37.     if (sb != cur_blkno) {
  38.         /*
  39.          * We have to read the block.
  40.          */
  41.         next_blkno = dds_getpos(device);
  42.         /*
  43.          * next_blkno stores now the number of the next block of the
  44.          * tape.
  45.          */
  46.         n = sb - next_blkno;
  47.         /*
  48.          * In some cases reading is faster then seeking.
  49.          */
  50.         if ((n > 0) && (n < DONT_SKIP)) {
  51.             do {
  52.                 dds_read_block();
  53.             } while ((--n) > 0);
  54.         }
  55.         /*
  56.          * Now we should be at the position.
  57.          */
  58.         n = sb - next_blkno;
  59.         if (n != 0) {
  60.             dds_seek(device, sb);
  61.             next_blkno = sb;
  62.         }
  63.         /*
  64.          * Now we read the block. cur_n == 0 indicates a filemark.
  65.          */
  66.         dds_read_block();
  67.     }
  68.     return 0;
  69. }
  70.  
  71. /*
  72.  * procedure to extract the files from the specified area (sb:sr-eb:er).
  73.  * If area is of the form (sb:sr-0:0), the file at position (sb,sr) is
  74.  * extracted. The length of the file is read from the tar header record.
  75.  *
  76.  * If list_only is set to 1, only the name of the extraction is printed.
  77.  */
  78. static int
  79. extract(char const *const name, int const sb, int const sr)
  80. {
  81.  
  82.     int     cur_rec, n, size;
  83.     char   *p;
  84.  
  85. #ifdef DDS_TRACE
  86.     fprintf(stderr,"%d\n",__LINE__);
  87.     fprintf(stderr, "extract(%s,%d,%d)\n", name, sb, sr);
  88. #endif
  89.  
  90.     /*
  91.      * Print only the name.
  92.      */
  93.     if (list_only == 1) {
  94.         printf("%7d%3d: %s\n", sb, sr, name);
  95.         return 0;
  96.     }
  97.     /*
  98.      * Print the filename and the location for verbose output.
  99.      */
  100.     if (verbose != 0) {
  101.         fprintf(stderr,
  102.             "dds2tar at rec %d: %7d%3d: %s\n",
  103.             nblocks, sb, sr, name);
  104.     }
  105.     /*
  106.      * Check the buffer for the right tape block.
  107.      */
  108.     set_cur_block(sb);
  109.  
  110.     cur_rec = sr;
  111.     /*
  112.      * Check the header block.
  113.      * The Name field should contain the given name.
  114.      * The Program will stop if its not.
  115.      *
  116.      * Note that for links we can only compare the first
  117.      * characters, when the index contains somethins like
  118.      * 'linkname -> filename' (soft link) or
  119.      * 'linkname link to filename' (hard link)
  120.      * doesn't match 'linkname'.
  121.      */
  122.     p = (char*) (cur_block + cur_rec) ;
  123.     if ( dds_is_tar_header_record((tar_record*)p) == 0 ) {
  124.         fprintf(stderr,
  125.             " dds2tar: FATAL ERROR\n"
  126.             " dds2tar: header expected, not found\n"
  127.         );
  128.         if ( force_nochk == 0 ) exit(5);
  129.     }
  130.     if (name != NULL)
  131.     if ( ( (strcmp(name, p)!=0 )
  132.         && (((tar_record*)p)->hdr.linkflag!='2')
  133.         && (((tar_record*)p)->hdr.linkflag!='1')
  134.         ) || ( strstr(name, p)!=name ) ) {
  135.         fprintf(stderr,
  136.             "dds2tar: FATAL ERROR\n"
  137.             "dds2tar: looked for %s at %d %d\n"
  138.             "dds2tar: not found %s at %d %d\n"
  139.             "dds2tar: Is it the right tape?\n",
  140.             name, sb , sr ,
  141.             name, dds_getpos(device) - 1, cur_rec);
  142.         if ( force_nochk == 0 ) exit(5);
  143.     }
  144.     /*
  145.      * First calculate the number of records of the object.
  146.      */
  147.     size = 0;
  148.     n = 1;
  149.  
  150.     p = cur_block[cur_rec].hdr.size;
  151.     if (*p != '\0') {
  152.         sscanf(p, "%o", &size);
  153.         n = size;
  154.         n += 1023;
  155.         n >>= 9;
  156.     }
  157.     /*
  158.      * Now write the records to stdout.
  159.      */
  160.     if (verbose) {
  161.         fprintf(stderr,
  162.             "dd2tar: %s needs %d blocks\n", name, n);
  163.     }
  164.     if ( write_body == 1 ) {
  165.         cur_rec++;
  166.         while ((size > 0) && (cur_n > 0)) {
  167.             if (cur_rec >= cur_bs) {
  168.                 dds_read_block();
  169.                 cur_rec = 0;
  170.             }
  171.             write(1, cur_block + cur_rec, (size>=512)? 512:size );
  172.             size -= 512 ;
  173.             cur_rec++;
  174.         }
  175.         exit(0);
  176.     }
  177.     while ((n > 0) && (cur_n > 0)) {
  178.         if (cur_rec >= cur_bs) {
  179.             dds_read_block();
  180.             cur_rec = 0;
  181.         }
  182.         write(1, cur_block + cur_rec, 512);
  183.         nblocks++;
  184.         n--;
  185.         cur_rec++;
  186.     }
  187.     return 0;
  188. }
  189.  
  190. #ifdef EXP_STUFF
  191. int
  192. extract_loc(char const *const *loc_list)
  193. {
  194.     int cur_rec ;
  195.  
  196.     while (*loc_list != NULL) {
  197.         int     eb, er, sb, sr;
  198.  
  199.         sscanf(*loc_list, "%u:%u-%u:%u", &sb, &sr, &eb, &er);
  200.         set_cur_block(sb);
  201.         cur_rec = sr ;
  202.         while (cur_n > 0) {
  203.             int     i;
  204.  
  205.             if ((cur_n & 0x1ff) != 0) {
  206.                 fprintf(stderr,
  207.                     "tape record size (%d) is not a"
  208.                     " multiple of tar records\n"
  209.                     , cur_n
  210.                     );
  211.                 close(device);
  212.                 exit(6);
  213.             }
  214.             i = cur_n >> 9;
  215.             if (cur_blkno == eb)
  216.                 i = er;
  217.             while (cur_rec < i) {
  218.                 write(1, cur_block + cur_rec++, 512);
  219.                 nblocks++;
  220.             }
  221.             /*
  222.              * if eb==-1 extract until eof
  223.              */
  224.             if ((cur_rec == er && cur_blkno == eb))
  225.                 break;
  226.             i = cur_blkno + 1;
  227.             cur_rec = 0;
  228.             if ((cur_rec == er && cur_blkno == eb))
  229.                 break;
  230.             dds_read_block();
  231.         }
  232.         loc_list++;
  233.     }
  234.     return 0;
  235. }
  236.  
  237. #endif
  238.  
  239. /*
  240.  * Now we are scanning the table of contents (index file) and match the
  241.  * pathnames there with the given pattern. If a pattern matches, we
  242.  * extract the parent directories (dir_extract()) and the file.
  243.  */
  244. int
  245. dds_cmp(char const *const *const pattern_list)
  246. {
  247.     int i ;
  248.     char *fgets_return_value ;
  249.     char const *const *p;
  250.  
  251.     /*
  252.      * To scan the line of the table of contents (index file)
  253.      * we need some variables.
  254.      */
  255.     char   *name = NULL;
  256.     int     blkno, recno, size;
  257.  
  258.     /*
  259.      * List of directories entries.
  260.      */
  261.     struct dir_list {
  262.         char    n[128-2*sizeof(int)];    /* name of the dir */
  263.         int     b, r;    /* block address */
  264.     }
  265.            *dl;
  266.     int     de = 0;        /* first empty list entry */
  267.  
  268.     /*
  269.      * Format of the table of contents.
  270.      *      dds2index --> tar_index_file == 0
  271.      *      tar -Rvt  --> tar_index_file == 1
  272.      */
  273.     int     tar_index_file = 1;
  274.  
  275.     /*
  276.      * Bug fix for tar. First record number found inside the
  277.      * table of contents (index file).
  278.      */
  279.     int     tar_first_recno = -1;
  280.  
  281. #ifdef DDS_TRACE
  282.     fprintf(stderr,"%d\n",__LINE__);
  283.     fprintf(stderr,"dds_cmp(%s ...)\n",*pattern_list);
  284. #endif
  285.  
  286.  
  287.     /*
  288.      * First we need some memory.
  289.      */
  290.     dl = malloc(sizeof (*dl) * 64);
  291.     if (dl == NULL) {
  292.         close(device);
  293.         fprintf(stderr, "dds2tar: no address space available\n");
  294.         exit(7);
  295.     }
  296.     memset(cur_line, 0, 1024);
  297.  
  298.     /*
  299.      * Scan the table of conten|s (index file) until eof.
  300.      */
  301. #ifdef DDS_TRACE
  302.     fprintf(stderr,"%d\n",__LINE__);
  303. #endif
  304.     while (!feof(index_fp)) {
  305.         fgets_return_value = fgets(cur_line, 1024, index_fp);
  306.         if ( fgets_return_value == NULL ) {
  307.             if ( feof(index_fp) ) {
  308.                 break ;
  309.             } else {
  310.                 perror("dds2tar");
  311.                 exit(1);
  312.             }
  313.         }
  314. #ifdef DDS_TRACE
  315.         fprintf(stderr,"%d\n",__LINE__);
  316.         fputs(cur_line, stderr);
  317. #endif
  318.  
  319.         /*
  320.          * Check for comment and empty lines.
  321.          */
  322.         if ((*cur_line == '#') ||
  323.             (*cur_line == ' ') ||
  324.             (*cur_line == '\0'))
  325.             continue;
  326.  
  327.         /*
  328.          * Check the line for location information.
  329.          */
  330. #ifdef DDS_TRACE
  331.     fprintf(stderr,"%d\n",__LINE__);
  332. #endif
  333.         if (0 == rt_loc_line())
  334.             continue;
  335.  
  336.         /*
  337.          * Check for the first line of the dds2index.
  338.          */
  339.         if ((0 == strcmp(cur_line, dds_headline)) 
  340.         || (0 == strcmp(cur_line, dds_old_headline))) {
  341.             tar_index_file = 0;
  342.             tar_n = buf_n ;
  343.             tar_bs = buf_n >> 9 ;
  344.             continue;
  345.         }
  346. #ifdef DDS_TRACE
  347.         fprintf(stderr,"%d\n",__LINE__);
  348. #endif
  349.  
  350.         /*
  351.          * dds2index indicates eof with the string '-end-'.
  352.          * This line has to be processed in the normal way.
  353.          * We can stop now processing.
  354.          */
  355.         if ((*cur_line == '-') &&
  356.             (strncmp(cur_line, "-end-", 5) == 0)) {
  357. #ifdef DDS_TRACE
  358.             fprintf(stderr,"%d\n",__LINE__);
  359. #endif
  360.             break;
  361.         }
  362.  
  363.         /*
  364.          * Scan the line of the index.
  365.          * Note: The index file of dds2index contains the magic string
  366.          *   of the tar header, witch depends on the used tar version.
  367.          */
  368.         if (tar_index_file == 0) {
  369.             rt_line(&blkno, &recno, &size, &name);
  370.         } else {
  371.             /*
  372.              * check for record line
  373.              */
  374.             if (0 != strncmp(cur_line, "rec", 3))
  375.                 continue;
  376.  
  377.             recno = atoi(cur_line + 4);
  378.             /*
  379.               * Now we are fixing a bug of gnu tar ...
  380.              * The first number should be zero, othewise we
  381.              * correct all the numbers.
  382.              * If tar_first_recno is .lt. zero, no recno is read
  383.              * up to now.
  384.              */
  385.             if (tar_first_recno < 0)
  386.                 tar_first_recno = recno;
  387.             recno -= tar_first_recno;
  388.             /*
  389.              * Calculate the block number of the record.
  390.              */
  391.             blkno = recno / tar_bs;
  392.             recno -= blkno * tar_bs;
  393.             blkno += tar_fb;
  394.             if (name == NULL) {    /* calculate only once */
  395.                 if ( strlen(cur_line) >= 66 ) {
  396.                     name = cur_line + 65;
  397.                     while ( ( name[ 0] != '\0' )
  398.                      && (       ( name[-1] != ' '  )
  399.                         || ( name[-6] != ' '  )
  400.                         || ( name[-9] != ':'  )
  401.                      )
  402.                     ) name++ ;
  403.                     if ( name[-9] != ':' ) {
  404.                         name = cur_line + 16;
  405.                     }
  406.                 } else {
  407.                     name = cur_line + 16;
  408.                 }
  409.             }
  410.             while ( ( name[ 0] != '\0' )
  411.              &&     ( name != ( cur_line + 16 ) )
  412.              && (       ( name[-1] != ' '  )
  413.                 || ( name[-6] != ' '  )
  414.                 || ( name[-9] != ':'  )
  415.              )
  416.             ) name++ ;
  417.         }
  418. #ifdef DDS_TRACE
  419.         fprintf(stderr,"%d\n",__LINE__);
  420. #endif
  421.         i = strlen(name) -1 ;
  422.         if (name[i] == '\n') name[i] = '\0', i-- ;
  423.         /*
  424.          * We leave the list of directories empty on quick mode.
  425.          */
  426.         if (( name[i] == '/' )&&( quick_mode == 0 )) {
  427.             struct dir_list *dp;
  428.             for (i = 0 , dp = dl ; i < de; i++ , dp ++ ) {
  429.                 if (strstr(name, dp->n) != name)
  430.                     break;
  431.             }
  432.             strcpy(dp->n, name);
  433.             dp->b = blkno;
  434.             dp->r = recno;
  435.             de = i + 1 ;
  436.         }
  437.         /*
  438.          * Now we try to match one pattern with the name.
  439.          */
  440. #ifdef DDS_TRACE
  441.         fprintf(stderr,"%d\n",__LINE__);
  442.         fprintf(stderr,"scanning pattern list for '%s'\n",name);
  443. #endif
  444.         p = pattern_list;
  445.         while (*p != NULL) {
  446. #ifdef DDS_TRACE
  447.             fprintf(stderr," p = '%p' , *p = %p \n",p,*p);
  448. #endif
  449.             /*
  450.              * Thanks Andreas Bagge for this trick.
  451.              * I use the fnmatch function from the
  452.              * source of gnu tar.
  453.              */
  454. #ifdef DDS_TRACE
  455.             fprintf(stderr,"fnmatch for '%s'\n",*p);
  456. #endif
  457.             if (0 == fnmatch(*p, name, FNM_LEADING_DIR)) {
  458.                 struct dir_list *dp;
  459.                 for (i = 0, dp = dl; i < de; i++, dp++) {
  460.                     char   *p = strstr(name, dp->n);
  461.                     if (p == name) {
  462.                         extract(dp->n, dp->b, dp->r);
  463.                     } else break ;
  464.                 }
  465.                 de = 0;
  466.                 extract(name, blkno, recno);
  467.                 break;
  468.             }
  469.             p++;
  470.         }
  471. #ifdef DDS_TRACE
  472.         fprintf(stderr,"end of scanning pattern list\n");
  473. #endif
  474.     }
  475.     /*
  476.      * Write an empty record to the end of the archive.
  477.      */
  478.     memset(cur_block, 0, buf_n );
  479.     write(1, cur_block, 512);
  480.     nblocks++;
  481.     if (verbose)
  482.         fprintf(stderr, "dds2tar: %d blocks written\n", nblocks);
  483. #ifdef DDS_TRACE
  484.     fprintf(stderr,"%d\n",__LINE__);
  485.     fprintf(stderr,"return of dds_cmp(...)");
  486. #endif
  487.     return 0;
  488. }
  489.